package sg.edu.nus.iss.billing.gui;

import java.io.FileInputStream;
import java.util.*;
import java.util.List;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;

import sg.edu.nus.iss.billing.BillingApplication;
import sg.edu.nus.iss.billing.BillingConstants;
import sg.edu.nus.iss.billing.BillingConstants.SearchTypes;
import sg.edu.nus.iss.billing.BillingConstants.SearchSortBy;
import sg.edu.nus.iss.billing.BillingConstants.SystemState;
import sg.edu.nus.iss.billing.controller.BillController;
import sg.edu.nus.iss.billing.controller.CustAccountController;
import sg.edu.nus.iss.billing.exceptions.ControllerException;
import sg.edu.nus.iss.billing.model.account.Account;
import sg.edu.nus.iss.billing.model.account.AccountSorter;
import sg.edu.nus.iss.billing.model.account.Account.CustomerStatus;
import sg.edu.nus.iss.billing.model.user.User.SystemRole;

/**
 * @author Yeo Hee Ling, Ananda, Saravana
 *
 */
public class SearchCustomerPanel extends JPanel implements ActionListener, ListSelectionListener {
	private static String NONE = "NONE";
	private static final long serialVersionUID = 1L;
	private Properties properties;
	private SearchTypes searchType;
	private BillingApplication billingAppl;
	
	private JButton btnSearch, btnViewCustomer, btnEditCustomer, btnManageSubscription, btnSubscriptionHistory, btnViewBill,btnComplainCustomer;
	private JLabel lblAccount, lblName, lblNric, lblCustStatus, lblOrderBy;
	private JTextField txtAccount, txtName, txtNric;
	private JComboBox cbCustStatus, cbOrderBy, cbAvailableBill;
	private String[] custStatusOption = {"", CustomerStatus.ACTIVE.toString(), CustomerStatus.INACTIVE.toString()};
	private String[] custOrderByOption = {SearchSortBy.ACCOUNT_NO.toString(), SearchSortBy.NRIC.toString(), SearchSortBy.NAME.toString()};
	
	private JPanel resultPanel;
	private DefaultTableModel defaultTableModel = new DefaultTableModel() {
		private static final long serialVersionUID = 1L;
		
		public boolean isCellEditable(int row, int column) {
			return false;
		}
	};
	private JTable resultTable = new JTable(defaultTableModel);
	
	public SearchCustomerPanel(BillingApplication billingAppl, SearchTypes searchType) {
		this.billingAppl = billingAppl;
		this.searchType = searchType;
		this.setOpaque(false);
		
		loadConfiguration();
		
		resultTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		if(searchType == SearchTypes.VIEW_BILL) {
			resultTable.getSelectionModel().addListSelectionListener(this);
			resultTable.getColumnModel().getSelectionModel().addListSelectionListener(this);
		}
		
		this.setLayout(new BorderLayout());
		this.add(getHeaderPanel(), BorderLayout.NORTH);
		this.add(getSearchPanel(), BorderLayout.CENTER);
		
		resultPanel = new JPanel();
		resultPanel.setOpaque(false);
		this.add(resultPanel, BorderLayout.SOUTH);
	}
	
	public void actionPerformed(ActionEvent e) {
		if(e.getSource() == btnSearch) {
			String name = null;
			String nric = null;
			String accountNo = null;
			CustomerStatus status = null;
			String selectedSortOrder = cbOrderBy.getSelectedItem().toString();
			
			if (txtAccount.getText().trim().length() != 0){
				accountNo = txtAccount.getText().trim();
			}
			if (txtName.getText().trim().length() != 0){
				name = txtName.getText().trim();
			}
			if (txtNric.getText().trim().length() != 0){
				nric = txtNric.getText().trim();
			}
			if (cbCustStatus.getSelectedItem().toString().length() != 0) {
				status = CustomerStatus.valueOf(cbCustStatus.getSelectedItem().toString());
			}
			
			try {
				CustAccountController custAccountController = new CustAccountController();
				List<Account> matchedAccounts = custAccountController.searchExistingCustAccount(name, nric, accountNo, status);
				
				if(matchedAccounts != null && matchedAccounts.size() > 0) {
					Collections.sort(matchedAccounts, new AccountSorter(SearchSortBy.valueOf(selectedSortOrder)));
					resultPanel.removeAll();
					resultPanel.add(getResultPanel(matchedAccounts));
					resultPanel.getRootPane().revalidate();
				}
				else {
					resultPanel.removeAll();
					resultPanel.getRootPane().revalidate();
					JOptionPane.showMessageDialog(null, properties.getProperty("info.message.noRecord"), properties.getProperty("title.searchCustomer"), JOptionPane.INFORMATION_MESSAGE);
				}
			}
			catch(ControllerException ex) {
				JOptionPane.showMessageDialog(this, ex.getMessage(), properties.getProperty("title.searchCustomer"), JOptionPane.ERROR_MESSAGE);
				return;
			}
		}
		else if(e.getSource() == btnViewCustomer || e.getSource() == btnEditCustomer){
			int selectedRow = resultTable.getSelectedRow();
			if(selectedRow > -1){
				Account account = (Account)resultTable.getModel().getValueAt(selectedRow, 5);
				SystemState selectedMode = (e.getSource() == btnViewCustomer) ? SystemState.CUSTOMER_VIEW : SystemState.CUSTOMER_UPDATE;
				billingAppl.displayPage(new CustomerPanel(billingAppl, selectedMode, account, this));
			}
			else {
				JOptionPane.showMessageDialog(this, properties.getProperty("info.message.noSelection"), properties.getProperty("title.searchCustomer"), JOptionPane.INFORMATION_MESSAGE);
			}
		}
		else if(e.getSource() == btnManageSubscription){
			int selectedRow = resultTable.getSelectedRow();
			if(selectedRow > -1){
				Account account = (Account)resultTable.getModel().getValueAt(selectedRow, 5);
				billingAppl.displayPage(new SubscriptionPanel(billingAppl, account, this));
			}
			else {
				JOptionPane.showMessageDialog(this, properties.getProperty("info.message.noSelection"), properties.getProperty("title.searchCustomer"), JOptionPane.INFORMATION_MESSAGE);
			}
		}
		else if(e.getSource() == btnSubscriptionHistory){
			int selectedRow = resultTable.getSelectedRow();
			if(selectedRow > -1){
				Account account = (Account)resultTable.getModel().getValueAt(selectedRow, 5);
				billingAppl.displayPage(new SubscriptionHistoryPanel(billingAppl, account, this));
			}
			else {
				JOptionPane.showMessageDialog(this, properties.getProperty("info.message.noSelection"), properties.getProperty("title.searchCustomer"), JOptionPane.INFORMATION_MESSAGE);
			}
		}
		else if(e.getSource() == btnViewBill) {
			int selectedRow = resultTable.getSelectedRow();
			if(selectedRow > -1){
				Account account = (Account)resultTable.getModel().getValueAt(selectedRow, 5);
				String item = cbAvailableBill.getSelectedItem().toString();
				if(NONE.equals(item)) {
					JOptionPane.showMessageDialog(this, properties.getProperty("info.message.noBillGeneratedYet"), properties.getProperty("title.searchCustomer"), JOptionPane.INFORMATION_MESSAGE);
				}
				else {
					billingAppl.displayPage(new BillPanel(billingAppl, SystemState.BILL_VIEW, this, account, BillController.covertorToDateString(item)));
				}
			}
			else {
				JOptionPane.showMessageDialog(this, properties.getProperty("info.message.noSelection"), properties.getProperty("title.searchCustomer"), JOptionPane.INFORMATION_MESSAGE);
			}
		}
		else if(e.getSource() == btnComplainCustomer) {
			int selectedRow = resultTable.getSelectedRow();
			if(selectedRow > -1){
				Account account = (Account)resultTable.getModel().getValueAt(selectedRow, 5);
				billingAppl.displayPage(new ComplaintPanel(billingAppl,SystemState.COMPLAINT_ADD , null, this, account));
			}
			else {
				JOptionPane.showMessageDialog(this, properties.getProperty("info.message.noSelection"), properties.getProperty("title.searchCustomer"), JOptionPane.INFORMATION_MESSAGE);
			}
		}
	}
	
	private void loadConfiguration() {
		try {
			properties = new Properties();
			FileInputStream in = new FileInputStream(BillingConstants.PROPERTIES_CUSTOMER);
			properties.load(in);
			in.close();
		}
		catch(Exception ex) {
			ex.printStackTrace();
		}
	}
	
	public void valueChanged(ListSelectionEvent e) {
		// Only Listen to row selection.
		if(e.getSource() == resultTable.getSelectionModel() && resultTable.getRowSelectionAllowed()) {
			if(!e.getValueIsAdjusting()) {
				int selectedRow = resultTable.getSelectedRow();
				
				if(selectedRow != -1) {
					Account account = (Account)resultTable.getModel().getValueAt(selectedRow, 5);
					cbAvailableBill.removeAllItems();
					Set<String> viewBillString = account.getBillMap().keySet();
					TreeSet<String> sortedViewBillString = new TreeSet<String>();
					for(String date : viewBillString){
						sortedViewBillString.add(date);
					}
					if(sortedViewBillString != null && sortedViewBillString.size() > 0) {
						for(String period: sortedViewBillString) {
							cbAvailableBill.addItem(BillController.covertorToDateDisplay(period));
						}
					}
					else {
						cbAvailableBill.addItem(NONE);
					}
				}
			}
		}
	}
	
	public JPanel getHeaderPanel(){
		JPanel headerPanel = new JPanel();
		headerPanel.setLayout(new GridLayout(0, 1, 10, 10));
		headerPanel.setOpaque(false);
		
		JLabel msgLabel = new JLabel(properties.getProperty("title.searchCustomerAcct"));
		msgLabel.setFont(new Font("Tahoma", Font.BOLD, 18));
		msgLabel.setHorizontalAlignment(SwingConstants.CENTER);
		headerPanel.add(msgLabel);
		
		ImageIcon imgDivider = new ImageIcon("./images/divider.jpg");
		JLabel lblDivider = new JLabel(imgDivider);
		headerPanel.add(lblDivider);
		
		return headerPanel;
	}
	
	public JPanel getSearchPanel(){
		JPanel searchPanel = new JPanel();
		GridBagLayout layout = new GridBagLayout();
		searchPanel.setLayout(layout);
		searchPanel.setOpaque(false);
		
		GridBagConstraints constraints1 = new GridBagConstraints();
		constraints1.insets = new Insets(5, 5, 5, 5);
		constraints1.fill = GridBagConstraints.HORIZONTAL;
		
		GridBagConstraints constraints2 = new GridBagConstraints();
		constraints2.insets = new Insets(5, 5, 5, 50);
		constraints2.fill = GridBagConstraints.HORIZONTAL;
		
		constraints1.gridx = 0;
		constraints1.gridy = 0;
		lblAccount = new JLabel(properties.getProperty("label.customer.accountNo"));
		lblAccount.setHorizontalAlignment(JLabel.RIGHT);
		searchPanel.add(lblAccount, constraints1);
		
		constraints2.gridx = 1;
		constraints2.gridy = 0;
		txtAccount = new JTextField(20);
		txtAccount.setEditable(true);
		searchPanel.add(txtAccount, constraints2);
		
		constraints1.gridx = 2;
		constraints1.gridy = 0;
		lblName = new JLabel(properties.getProperty("label.customer.name"));
		lblName.setHorizontalAlignment(JLabel.RIGHT);
		searchPanel.add(lblName, constraints1);
		
		constraints2.gridx = 3;
		constraints2.gridy = 0;
		txtName = new JTextField(20);
		txtName.setEditable(true);
		searchPanel.add(txtName, constraints2);

		constraints1.gridx = 0;
		constraints1.gridy = 1;
		lblNric = new JLabel(properties.getProperty("label.customer.nric"));
		lblNric.setHorizontalAlignment(JLabel.RIGHT);
		searchPanel.add(lblNric, constraints1);
		
		constraints2.gridx = 1;
		constraints2.gridy = 1;
		txtNric = new JTextField(20);
		txtNric.setEditable(true);
		searchPanel.add(txtNric, constraints2);
		
		constraints1.gridx = 2;
		constraints1.gridy = 1;
		lblCustStatus = new JLabel(properties.getProperty("label.customer.acctStatus"));
		lblCustStatus.setHorizontalAlignment(JLabel.RIGHT);
		searchPanel.add(lblCustStatus, constraints1);
		
		constraints2.gridx = 3;
		constraints2.gridy = 1;
		if(searchType == SearchTypes.COMPLAINTS) {
			cbCustStatus = new JComboBox();
			cbCustStatus.addItem(CustomerStatus.ACTIVE);
		}
		else {
			cbCustStatus = new JComboBox(custStatusOption);
		}
		searchPanel.add(cbCustStatus, constraints2);
		
		constraints1.gridx = 0;
		constraints1.gridy = 2;
		lblOrderBy = new JLabel(properties.getProperty("label.customer.orderBy"));
		lblOrderBy.setHorizontalAlignment(JLabel.RIGHT);
		searchPanel.add(lblOrderBy, constraints1);
		
		constraints2.gridx = 1;
		constraints2.gridy = 2;
		cbOrderBy = new JComboBox(custOrderByOption);
		searchPanel.add(cbOrderBy, constraints2);
		
		GridBagConstraints constraints3 = new GridBagConstraints();
		constraints3.insets = new Insets(20, 5, 20, 5);
		constraints3.gridwidth = 4;
		constraints3.gridy = 3;
		constraints3.anchor = GridBagConstraints.CENTER;
		btnSearch = new JButton(properties.getProperty("label.customer.searchDB"));
		btnSearch.setPreferredSize(new Dimension(175, 25));
		btnSearch.addActionListener(this);
		searchPanel.add(btnSearch, constraints3);
		return searchPanel;
	}
	
	public JPanel getResultPanel(List<Account> matchedAccounts){
		String[] columnNames = {"No", "Account No.", "Name", "NRIC", "Status", "AccountObject"};
		
		Object[][] data = new Object[matchedAccounts.size()][6];
		for(int n = 0; n < matchedAccounts.size(); n++) {
			Account account = matchedAccounts.get(n);
			
			data[n][0] = String.valueOf(n+1);
			data[n][1] = account.getAccountNo();
			data[n][2] = account.getCustomerName();
			data[n][3] = account.getCustomerNRIC();
			data[n][4] = account.getStatus();
			data[n][5] = account;
		}
		
		defaultTableModel.setDataVector(data, columnNames);
		resultTable.setModel(defaultTableModel);
		resultTable.removeColumn(resultTable.getColumnModel().getColumn(5)); // Not to display to Column.
		resultTable.setPreferredScrollableViewportSize(new Dimension(900,350));
		
		JPanel searchResultPanel = new JPanel();
		searchResultPanel.setOpaque(false);
		searchResultPanel.setLayout(new BorderLayout());
		searchResultPanel.add(new JScrollPane(resultTable), BorderLayout.NORTH);
		JPanel actionBtnPanel = new JPanel();
		actionBtnPanel.setOpaque(false);
		
		if(searchType == SearchTypes.EXISTING_ACC) {
			btnViewCustomer = new JButton(properties.getProperty("label.customer.button.view"));
			btnViewCustomer.setPreferredSize(new Dimension(175, 25));
			btnViewCustomer.addActionListener(this);
			actionBtnPanel.add(btnViewCustomer);
			
			if(BillingApplication.getUserSession().getSystemRole() == SystemRole.ADMIN){
				btnEditCustomer = new JButton(properties.getProperty("label.customer.button.edit"));
				btnEditCustomer.setPreferredSize(new Dimension(175, 25));
				btnEditCustomer.addActionListener(this);
				actionBtnPanel.add(btnEditCustomer);
				
				btnManageSubscription = new JButton(properties.getProperty("label.customer.button.manageSubscription"));
				btnManageSubscription.setPreferredSize(new Dimension(175, 25));
				btnManageSubscription.addActionListener(this);
				actionBtnPanel.add(btnManageSubscription);
			}
			searchResultPanel.add(actionBtnPanel, BorderLayout.SOUTH);
		}
		
		if(searchType == SearchTypes.SUBSCRIPTIONS) {
			btnManageSubscription = new JButton(properties.getProperty("label.customer.button.manageSubscription"));
			btnManageSubscription.setPreferredSize(new Dimension(175, 25));
			btnManageSubscription.addActionListener(this);
			actionBtnPanel.add(btnManageSubscription);
			
			btnSubscriptionHistory = new JButton(properties.getProperty("label.customer.button.viewSubscriptionHistory"));
			btnSubscriptionHistory.setPreferredSize(new Dimension(200, 25));
			btnSubscriptionHistory.addActionListener(this);
			actionBtnPanel.add(btnSubscriptionHistory);
			
			searchResultPanel.add(actionBtnPanel, BorderLayout.SOUTH);
		}
		
		if(searchType == SearchTypes.VIEW_BILL) {
			JLabel lblAvailableBill = new JLabel(properties.getProperty("label.customer.availableBill"));
			actionBtnPanel.add(lblAvailableBill);
			
			cbAvailableBill = new JComboBox();
			cbAvailableBill.setPreferredSize(new Dimension(175, 25));
			actionBtnPanel.add(cbAvailableBill);
			
			btnViewBill = new JButton(properties.getProperty("label.customer.button.viewBill"));
			btnViewBill.setPreferredSize(new Dimension(175, 25));
			btnViewBill.addActionListener(this);
			actionBtnPanel.add(btnViewBill);
			searchResultPanel.add(actionBtnPanel, BorderLayout.SOUTH);
		}
		
		if(searchType == SearchTypes.COMPLAINTS) {
			btnComplainCustomer = new JButton(properties.getProperty("label.customer.button.addComplaint"));
			btnComplainCustomer.setPreferredSize(new Dimension(175, 25));
			btnComplainCustomer.addActionListener(this);
			actionBtnPanel.add(btnComplainCustomer);
			searchResultPanel.add(actionBtnPanel, BorderLayout.SOUTH);
		}
		return searchResultPanel;
	}
}
